//
//  iOSRenderSystem.cpp
//  GSEngine
//
//  Created by Гукун Александр on 1/27/14.
//  Copyright (c) 2014 SNK. All rights reserved.
//

#include "iOSRenderSystem.h"
#include <GSEngine/Objects/EntityManager.h>
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>

namespace GSEngine
{
    iOSRenderSystem::iOSRenderSystem()
    {
        std::cout << "iOSrenderSystem created\n";
    }
    
    iOSRenderSystem::~iOSRenderSystem()
    {
        std::cout << "iOSrenderSystem destroyed\n";
    }
    
    void iOSRenderSystem::initWithWindow(size_t width, size_t height)
    {
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);
        //glClearColor(1, 1, 0, 1);
        Camera* camera = EntityManager::getInstance()->getCamera();
        camera->setPosition(vec3f(0.0f, 0.0f, 20.0f));
        camera->updateWorldMatrix();
        camera->updateViewMatrix();

        m_projMatrix = calcPerspProjMatrix(M_PI_2, float(width)/float(height), 0.1f, 1000.0f);
//        m_projMatrix = calcOrthoProjMatrix(-20, 20, -20, 20, -20, 20);
    }
    
    void iOSRenderSystem::render(GSRenderedObject* object)
    {
        //std::cout << "\n" << object->getName();
        //clear(BUFFER_BIT) вызывается перед началом рендера каждого обьекта в диспетчере узлов
        //принимает обьект для вывода на экран
        //вызываем Use Program
        //передать в шейдер матрици: проекции, мировую
        //мировая обьекта умножается на матрицу вида(обратная мировая камеры)
        object->updateWorldMatrix();
        glUseProgram(object->getShaderProgram());
        Camera* camera = EntityManager::getInstance()->getCamera();
        
        glUniformMatrix4fv(glGetUniformLocation(object->getShaderProgram(), "viewMatrix"), 1, 0, camera->getViewMatrix().m);
        glUniformMatrix4fv(glGetUniformLocation(object->getShaderProgram(), "worldMatrix"), 1, 0, object->getWorldMatrix().m);
        glUniformMatrix4fv(glGetUniformLocation(object->getShaderProgram(), "projMatrix"), 1, 0, m_projMatrix.m);

        
        glEnableVertexAttribArray(glGetAttribLocation(object->getShaderProgram(), "coord"));
        glVertexAttribPointer(glGetAttribLocation(object->getShaderProgram(), "coord"), 3, GL_FLOAT, GL_FALSE, 0, object->getVertexCoords());
        glEnableVertexAttribArray(glGetAttribLocation(object->getShaderProgram(), "textCoord"));
        glVertexAttribPointer(glGetAttribLocation(object->getShaderProgram(), "textCoord"), 2, GL_FLOAT, GL_FALSE, 0, object->getTextureCoords());
        
        glBindTexture(GL_TEXTURE_2D, object->getTexture());
        glUniform1i(glGetUniformLocation(object->getShaderProgram(), "g_texture"), 0);
        
        switch (object->getType()) {
            case ESpriteEntity:
                glDrawArrays(GL_TRIANGLE_FAN, 0, object->getVertexCount());
                break;
            case EModelEntity:
                glDrawElements(GL_TRIANGLES, object->getIndicesCount(), GL_UNSIGNED_SHORT, object->getIndices());
                break;
                
            default:
                break;
        }
        
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        
        glUseProgram(0);
        //передаем координаты вершин через атрибуты вершины
        //передаем текстурные координаты через атрибуты вершины
        //передаем координаты нормалей через атрибуты вершины
        //передаем текстуру семплером(сделать позже)
        //draw arrays рисуем примитивы
    }
    // create orthogonal projection matrix
    mat4 iOSRenderSystem::calcOrthoProjMatrix(float left, float right, float bottom, float top, float near, float far)
    {
        float Sx = 2/(right-left);
        float Sy = 2/(top-bottom);
        float Sz = -2/(far-near);
        float Tx = -(right + left) / (right - left);
        float Ty = -(top + bottom) / (top - bottom);
        float Tz = -(far + near)   / (far - near);
        mat4 result = { Sx,    0.0f,  0.0f,  0.0f,
                        0.0f,  Sy,    0.0f,  0.0f,
                        0.0f,  0.0f,  Sz,    0.0f,
                        Tx,    Ty,    Tz,    1.0f };
        return result;

    }
    // create perspective projection matrix
    mat4 iOSRenderSystem::calcPerspProjMatrix(float fovy, float aspect, float nearZ, float farZ)
    {
        float cotan = 1.0f / tanf(fovy / 2.0f);
        float diffZ = nearZ - farZ;
        mat4 result = { cotan / aspect, 0.0f,  0.0f,                          0.0f,
                        0.0f,           cotan, 0.0f,                          0.0f,
                        0.0f,           0.0f,  (farZ + nearZ) / diffZ,       -1.0f,
                        0.0f,           0.0f,  (2.0f * farZ * nearZ) / diffZ, 0.0f };
        return result;    }
}